<?php


namespace App\Http\Library;


class Curl
{

    /*请求url地址*/
    public static $url = '';
    /*url路径参数*/
    public static $urlParam = [];
    /*formData参数*/
    public static $bodyParam = [];
    /*上传文件*/
    public static $bodyFile = [];
    /*formData参数是否需要json化*/
    public static $bodyParamIsJson = true;
    /*自定义请求头*/
    public static $requestHeader = [];
    /*返回响应头*/
    public static $responseHeader = false;
    /*响应时间组成的简要模型*/
    public static $responseTimeInfo = null;
    /*设置请求超时时间,超过此上限则,强制中断连接(毫秒)*/
    public static $timeOutConfine = 1000 * 20;
    /*设置触发日志记录时间(秒)*/
    public static $timeOut = 15;
    /*返回结果*/
    private static $responseInfo = null;
    /*curl异常*/
    private static $errno = false;
    /*默认请求头*/
    private static $initHeader = [
        'Content-Type' => 'application/json; charset=utf-8',
        'User-Agent'   => 'TAL-API(jessica)'
    ];
    /*最终请求头*/
    private static $lastHeader = [];
    private static $curl = true;


    /**
     * 参数重新初始化
     */
    private static function initParam()
    {

        self::$url = '';
        self::$urlParam = [];
        self::$bodyParam = [];
        self::$bodyFile = [];
        self::$bodyParamIsJson = true;
        self::$requestHeader = [];
        self::$responseHeader = false;
        self::$responseTimeInfo = null;
        self::$timeOutConfine = 1000 * 20;
        self::$timeOut = 15;
        self::$initHeader = [
            'Content-Type' => 'application/json; charset=utf-8',
            'User-Agent'   => 'TAL-API(jessica)'
        ];

    }


    /**
     * 设置请求地址&GET参数处理
     *
     * @return string
     */
    private static function getUrl()
    {

        if (empty(self::$urlParam)) {
            return self::$url;
        } else {
            /*GET参数处理*/
            //echo self::$url . '?' . http_build_query(self::$urlParam);die;
            return self::$url . '?' . http_build_query(self::$urlParam);
        }

    }


    /**
     * body参数处理
     */
    private static function setBodyParam()
    {

        if (empty(self::$bodyParam)) {
            return true;
        }

        if (self::$bodyParamIsJson) {
            if (is_string(self::$bodyParam)) {
                curl_setopt(self::$curl, CURLOPT_POSTFIELDS, self::$bodyParam);
                self::$initHeader['Content-Length'] = strlen(self::$bodyParam);
            } else {
                $bodyParam = json_encode(self::$bodyParam);
                curl_setopt(self::$curl, CURLOPT_POSTFIELDS, $bodyParam);
                self::$initHeader['Content-Length'] = strlen($bodyParam);
            }
        } else {
            $bodyParam = http_build_query(self::$bodyParam);
            curl_setopt(self::$curl, CURLOPT_POSTFIELDS, $bodyParam);
            self::$initHeader['Content-Length'] = strlen($bodyParam);
        }

        curl_setopt(self::$curl, CURLOPT_POST, 1);

    }


    /**
     * 设置请求头
     */
    private static function setHeader()
    {
        $headers = array_merge(self::$initHeader, self::$requestHeader);
        self::$lastHeader = [];

        foreach ($headers as $key => $val) {
            self::$lastHeader[] = "{$key}:{$val}";
        }
        unset($headers);
        curl_setopt(self::$curl, CURLOPT_HTTPHEADER, self::$lastHeader);
    }


    /**
     * 设置毫秒超时
     */
    private static function setTimeOut()
    {

        curl_setopt(self::$curl, CURLOPT_NOSIGNAL, 1);
        curl_setopt(self::$curl, CURLOPT_TIMEOUT_MS, self::$timeOutConfine);

    }


    /**
     * SSL证书
     */
    private static function setSSL()
    {

        $isSsl = substr(self::$url, 0, 8) == "https://" ? true : false;

        if ($isSsl) {
            curl_setopt(self::$curl, CURLOPT_SSL_VERIFYPEER, true);
            curl_setopt(self::$curl, CURLOPT_SSL_VERIFYHOST, 2);
        }

    }


    /**
     * 上传文件
     */
    private static function fileUpload()
    {
        if (empty(self::$bodyFile)) {
            return;
        }
        self::$initHeader['Content-Type'] = 'multipart/form-data';
        $data = [];
        foreach (self::$bodyFile as $key => $val) {
            $data[$key] = curl_file_create($val, mime_content_type($val), basename($val));
            //$data[$key] = new \CURLFile($val, mime_content_type($val), basename($val));
        }
        curl_setopt(self::$curl, CURLOPT_POST, true);
        curl_setopt(self::$curl, CURLOPT_POSTFIELDS, $data);
    }


    /**
     * 提交
     *
     * @return mixed|null
     */
    public static function commit(&$header = '')
    {

        /*初始化*/
        self::$curl = curl_init();
        /*设置请求地址&GET参数处理*/
        curl_setopt(self::$curl, CURLOPT_URL, self::getUrl());
        /*SSL证书*/
        self::setSSL();
        /*检查是否存在body参数*/
        self::setBodyParam();
        /*是否需要上传文件*/
        self::fileUpload();
        /*设置请求头*/
        self::setHeader();
        /*设置头文件信息数据流输出方式*/
        curl_setopt(self::$curl, CURLOPT_HEADER, (int) self::$responseHeader);
        /*设置为结果不直接输出*/
        curl_setopt(self::$curl, CURLOPT_RETURNTRANSFER, 1);
        /*允许重定向*/
        curl_setopt(self::$curl, CURLOPT_FOLLOWLOCATION, true);
        /*重定向上限*/
        curl_setopt(self::$curl, CURLOPT_MAXREDIRS, 6);
        /*设置毫秒超时*/
        self::setTimeOut();
        self::$responseInfo = curl_exec(self::$curl);
        /*获取请求时间*/
        self::$responseTimeInfo = curl_getinfo(self::$curl);
        /*获取异常*/
        self::$errno = curl_errno(self::$curl);
        curl_close(self::$curl);
        /*响应头处理*/
        if (self::$responseHeader === true && isset(self::$responseTimeInfo['header_size'])) {
            /*截取响应头*/
            $header = substr(self::$responseInfo, 0, self::$responseTimeInfo['header_size']);
            /*截取正文*/
            self::$responseInfo = substr(self::$responseInfo, self::$responseTimeInfo['header_size']);
        }
        /*记录处理结果*/
        self::responseRecord();
        /*参数重新初始化*/
        self::initParam();
        return self::$responseInfo;

    }


    /**
     * 记录处理结果
     */
    private static function responseRecord()
    {
        /**
         * 请求发送失败 OR 指定记录日志 OR 触发超时记录
         * 则写入日志
         */
        if (self::$responseInfo === false || self::$errno != 0 || self::$timeOut < self::$responseTimeInfo['total_time']) {
            /*流日志记录方式处理*/
            if (isset(self::$responseTimeInfo['content_type']) && self::$responseTimeInfo['content_type'] == 'application/octet-stream') {
                $responseInfo = 'application/octet-stream:' . strlen(self::$responseInfo);
            } else {
                $responseInfo = empty(self::$responseInfo) ? self::$responseInfo : substr(self::$responseInfo, 0, 1024);
            }
            log_arr([
                'errno:' . self::$errno,
                /*获得用秒表示的上一次传输总共的时间，包括DNS解析、TCP连接等*/
                'total_time:' . self::$responseTimeInfo['total_time'],
                /*获得用秒表示的从最开始到域名解析完毕的时间*/
                'namelookup_time:' . self::$responseTimeInfo['namelookup_time'],
                /*获得用秒表示的从最开始直到对远程主机（或代理）的连接完毕的时间*/
                'connect_time:' . self::$responseTimeInfo['connect_time'],
                /*获得用秒表示的从最开始直到文件刚刚开始传输的时间*/
                'pretransfer_time:' . self::$responseTimeInfo['pretransfer_time'],
                /*获得用秒表示的从最开始到第一个字节被curl收到的时间*/
                'starttransfer_time:' . self::$responseTimeInfo['starttransfer_time'],
                /*获得所有用秒表示的包含了所有重定向步骤的时间，包括DNS解析、连接、传输前（pretransfer)和在最后的一次传输开始之前*/
                'redirect_time:' . self::$responseTimeInfo['redirect_time'],
                'request_url:' . self::$url,
                'get_param'     => self::$urlParam,
                'post_param'    => self::$bodyParam,
                'header_param'  => self::$lastHeader,
                'response_info' => $responseInfo
            ], 'curl');
        }

    }

}





/**
 * Curl.php
 *
 * 说明:
 *
 * 修改历史
 * ----------------------------------------
 * 2020/9/25 19:07:00   操作:创建
 **/
